R is an open source programming language that is popular for statistics and data analysis. R was built by statisticians, so many common statistical operations are built into the base language. R also features powerful and intuitive libraries for plotting and a variety of packages for predictive modeling, making it one of the most popular languages for data science.

Data Types

Decimal numbers (real numbers) in R are known as doubles. Doubles are the default numeric data type so when you manually enter a number in R, you are working with a double.

typeof(1)
[1] "double"
typeof(-10.5)
[1] "double"
typeof(Inf)
[1] "double"
typeof(-Inf)
[1] "double"
typeof(NaN) # dividing zero by zero produces NaN
[1] "double"

Integers are a second numeric data type that only take whole numbered values.

as.integer(1) # Convert the double 1 to integer 1
[1] 1
typeof(as.integer(1))
[1] "integer"
# Convert back from integer to double
as.numeric(as.integer(1))
[1] 1

Our first non-numeric data type is the Logical. A Logical takes on the value of TRUE or FALSE. You must type TRUE and FALSE in all capital letters for R to recognize them as logical values. Data that only takes on the values of True or False are also called “Booleans”.

typeof(TRUE)
[1] "logical"
typeof(FALSE)
[1] "logical"
typeof(T)
[1] "logical"
typeof(F)
[1] "logical"

You can create logical values with logical comparisons. R supports a variety of standard logic comparison operators including > (greater than), < (less than), >= (greater than or equal), <= (less than or equal).

20 > 20
[1] FALSE
20 >= 20
[1] TRUE
10 == 10
[1] TRUE
10 != 20
[1] TRUE
!FALSE
[1] TRUE
(2 > 1) & (10 == 9)
[1] FALSE
(2 > 1) | (10 == 9)
[1] TRUE

Strings of text in R are known as characters. Surround text with quotation marks to create a character.

typeof("cat")
[1] "character"
typeof("1")
[1] "character"
typeof(as.numeric("12"))
[1] "double"
typeof(as.character(12))
[1] "character"

Simple Arithmetic Operations¶

12 + 6 # addition
[1] 18
12 - 6 # subtraction
[1] 6
12 * 6 # multiplication
[1] 72
12 / 6 # division
[1] 2
12^6 # exponentiation
[1] 2985984
12**6 # exponentiation
[1] 2985984
12 %% 6 # modulo (get remainder)
[1] 0

Variables

A variable is a name you assign a value or object. After assigning a variable, you can access its associated value or object using the variable’s name. To simply put, this is how we store data. In R, assign variables using <- (the less than sign followed by a hyphen.).

var <- 3 + 3
x <- 10
y <- "R Workshop"
z <- (sqrt(144) == 12)

print(var)
[1] 6
print(x)
[1] 10
print(y)
[1] "R Workshop"
print(z)
[1] TRUE

It is possible to assign variables in R using the equals symbol = instead of <-. The equal sign is used for variable assignment in many other programming languages (such as Python). One reason for using <- besides conforming to the style preferred by the R community is that the equals sign is used in places other than variable assignment statements. Functions often take named arguments and when calling a function you use the = symbol to assign values to named arguments.

Vectors or Collections

A vector is a sequence of data elements of the same data type. You can have numeric, logical and character vectors.

To create and store a vector with specific values, use the c() function and assign the result to a variable. c() takes a comma separated sequence of elements as input and combines them into a vector. You can also combine two vectors using the c() function. If you try to combine vectors of different types, R will automatically convert the vectors into the type that fits best.

# Creating a character vector for the days of the week
weekday <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")

weekend <- c("Saturday", "Sunday")

days <- c(weekday, weekend)

print(days)
[1] "Monday"    "Tuesday"   "Wednesday" "Thursday"  "Friday"    "Saturday"  "Sunday"   

Vector Indexing Starts at 1

The first element is at index position 1, the second element is at index position 2 and so on.

*Note: unlike many other programming languages, indexes in R start at 1 instead of 0.

When you print a vector to the screen, each line starts with a number in square brackets followed by vector values. The number in square brackets indicates the index of the next value listed on that line.

You can access a specific value in a vector by typing the name of the vector and then wrapping the index associated with the value you want to access in square brackets.

days[1]
[1] "Monday"

Range of Values: Inclusive

You can access ranges of values by placing a colon between the starting and ending indices of the range:

days[1:3]
[1] "Monday"    "Tuesday"   "Wednesday"

Pulling out specific elements from Vectors

days[c(1, 3, 5, 7)]
[1] "Monday"    "Wednesday" "Friday"    "Sunday"   

Subset out of a Collection

A subset of a vector is just a shorter vector. You can access a specific subset of values by wrapping a vector in the square brackets.

weekdays <- days[1:5]
weekdays
[1] "Monday"    "Tuesday"   "Wednesday" "Thursday"  "Friday"   

Generate a vector using 100 random Numbers

random_data <- runif(100) # Create a vector of 100 random numbers

print(random_data)
  [1] 0.601253516 0.719215520 0.428791696 0.954586146 0.002825221 0.912358903 0.094981659 0.465619302 0.210666870 0.902174364 0.396719641 0.322112673 0.511106455
 [14] 0.521341122 0.363127518 0.366527548 0.527183666 0.685147211 0.519944513 0.591298793 0.061995111 0.302844349 0.880424201 0.365061312 0.463684499 0.804066397
 [27] 0.148957152 0.287857758 0.093952734 0.758151887 0.103074430 0.892897486 0.579773317 0.798398663 0.603510989 0.241194112 0.231561340 0.785641948 0.750667124
 [40] 0.190808424 0.629992959 0.855862409 0.412287503 0.960019909 0.404498031 0.570024413 0.959659815 0.174513218 0.053899949 0.672869894 0.142749767 0.654829003
 [53] 0.636226679 0.926860283 0.955050981 0.599153793 0.263378433 0.476719820 0.997212063 0.814981470 0.173799206 0.036244909 0.628301271 0.296626335 0.121297164
 [66] 0.512687834 0.130345278 0.447331684 0.881440107 0.949472001 0.755979348 0.818791750 0.915813698 0.853843003 0.740594027 0.806554129 0.891963726 0.786478848
 [79] 0.098086106 0.034598737 0.606487290 0.959551943 0.111269935 0.825509603 0.398758434 0.633334293 0.279467671 0.517837560 0.080050943 0.527193833 0.357329777
 [92] 0.862411802 0.275236687 0.071194843 0.681278336 0.465154053 0.468364371 0.391514763 0.098308521 0.022964923
print(length(random_data))
[1] 100

Filtering of Vectors using Logical Expressions You can also index a vector with a logical vector of the same length. In this case, the subset is created from each index where the corresponding logical vector is TRUE. Indexing with a logical vector is a common way to filter a numeric or character vector for values that fulfill certain criteria.

# Exclude everything except for your specified index

y <- c(1, 0, 3)
y <- y[-2]
y
[1] 1 3
# Exclude the range 2 to 9
random_data <- runif(50)
random_data_sub <- random_data[-(2:49)]
random_data_sub
[1] 0.2665789 0.3968453
# Exclude using logical expression
over_half <- (random_data > 0.5)
new_subset <- random_data[over_half]
new_subset
 [1] 0.9513518 0.9196884 0.6220517 0.6799197 0.8695307 0.7120434 0.8860579 0.5192011 0.6553047 0.8639851 0.6851627 0.7975867 0.8037875 0.5572514 0.9958366 0.5052394
[17] 0.5590207 0.9668272 0.6954043 0.7933677 0.6393207 0.9396667 0.8633686 0.7923260 0.7717887 0.9555974 0.9679353 0.8015830 0.5403477 0.7434739

Use %in% to filter a vector

my_letters <- c("a", "b", "c", "d", "a", "c")

# Get only the a's and c's
my_letters[my_letters %in% c("a", "c")]
[1] "a" "c" "a" "c"

Vectorized Operations

Many R functions and operations behave in a “vectorized” manner, meaning they act upon each element of a vector individually and return the result of each of the operations in a new vector. Vectorized operations simplify the process of performing the same calculations on related data. All the basic operators and functions we’ve learned so far that operate on single values work on vectors longer than length 1.

example_vector <- c(1, 2, 3)

# adds to each value in the vector
example_vector + 10
[1] 11 12 13
# performs subtraction on each value
example_vector - 10
[1] -9 -8 -7

Different Ways to Generate Vectors

x <- 1:20
y <- seq(from = 1, to = 20, by = 2)
r <- rep(1, times = 10)
s <- runif(n = 5, min = 0, max = 100)

x
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
y
 [1]  1  3  5  7  9 11 13 15 17 19
r
 [1] 1 1 1 1 1 1 1 1 1 1
s
[1] 74.66618 93.12643 14.42880 74.82574 60.27581

Control Flow

If, Else and Else If

An if statement checks whether some logical expression is true or false and executes a specified block of code if the logical expression is true.

In R, an if statement starts with if, followed by a logical expression in parentheses, followed by the code to execute when the if statement is true in curly braces.

If statements are often accompanied by else statements. Else statements come after if statements and allow you to execute code in the event that the logical expression of an if statement is false.

x <- 5
if (x > 0) {
  print("Positive number")
} else {
  print("Negative number")
}
[1] "Positive number"

For Loops

For loops are a programming construct that let you go through each item in a sequence and then perform some operation on each one.

my_sequence <- seq(0, 100, 10)

# Create a new loop over the specified items
for (item in my_sequence) {
  print(item)
}
[1] 0
[1] 10
[1] 20
[1] 30
[1] 40
[1] 50
[1] 60
[1] 70
[1] 80
[1] 90
[1] 100

The next keyword causes a for loop to skip to the next iteration of the loop.

my_sequence <- seq(0, 100, 10)
for (item in my_sequence) {
  if (item < 50) { # this if statement skips items less than 50
    next
  }
  print(item)
}
[1] 50
[1] 60
[1] 70
[1] 80
[1] 90
[1] 100

The break keyword halts the execution of the loop entirely. Use break to break out of a loop.

my_sequence <- seq(0, 100, 10)

for (item in my_sequence) {
  if (item > 50) {
    break
  }
  print(item)
}
[1] 0
[1] 10
[1] 20
[1] 30
[1] 40
[1] 50

While Loops

While loops are similar to for loops in that they allow you to execute code over and over again. For loops execute their contents, at most, a number of iterations equal to the length of the sequence you are looping over. While loops, on the other hand, keep executing their contents as long as a certain logical expression you supply remains true.

x <- 5
iterations <- 0

# Execute as long as iterations < x
while (iterations < x) {
  print("Study")
  iterations <- iterations + 1 # Increment iterations by 1 each time the loop executes
}
[1] "Study"
[1] "Study"
[1] "Study"
[1] "Study"
[1] "Study"

If Else on Vectors

For example, imagine you have a vector of numbers and you want to set all the negative values in the vector to zero. One way to do it is to use a for loop with an inner if statement.

my_vect <- runif(25, -1, 1) # Generate some random data between -1 and 1

for (index in 1:length(my_vect)) { # loop through the sequence 1:25
  number <- my_vect[index] # look up the next number using indexing
  if (number < 0) { # check if the number is less than 0
    my_vect[index] <- 0 # if so, set it to 0
  }
}

print(my_vect)
 [1] 0.0000000 0.0000000 0.9865759 0.3029479 0.5311695 0.0000000 0.8078285 0.0000000 0.6218120 0.0000000 0.0000000 0.0000000 0.3058018 0.0000000 0.0000000 0.5942243
[17] 0.0000000 0.0000000 0.0000000 0.0000000 0.6908745 0.4105624 0.6997950 0.0000000 0.8020392

Using a for loop requires writing quite a bit of code and loops are not particularly fast.

Instead we could have used R’s ifelse() function to the same thing in a vectorized manner. ifelse() takes a logical test as the first argument, a value to return if the test is true as the second argument and a value to return if the test is false as the third argument:

data <- c(11, 7, NA, 9, NA, 13, 15, NaN, 19, 17, 14, NaN)

# Use if else statements to conditionally fill these bad values with the mean

ifelse(is.na(data) | is.nan(data), # logical check
  mean(data, na.rm = T), # value to set if TRUE
  data
) # value to set if FALSE
 [1] 11.000  7.000 13.125  9.000 13.125 13.000 15.000 13.125 19.000 17.000 14.000 13.125
# Chaining ifelse to perform multiple operations
data <- c(11, 7, NA, 9, NA, 13, 15, NaN, 19, 17, 14, NaN)

d <- ifelse(is.na(data) | is.nan(data), "missing", ifelse(data < 10, "low", ifelse(data < 15, "medium", "high")))

table(d)
d
   high     low  medium missing 
      3       2       3       4 

Functions

A function is just an R object that runs a per-defined snippet of code, usually on some input that you supply to it. A function can return an output based on the input you provide. For example, the sum() function built into R simply takes a numeric vector as input and returns their sum as output. Built-in functions and packages can take you a long way in R, but it can be useful to define your own functions to perform specific tasks outside the scope of built-in functions.

Create your own function in R using this syntax:

# Assign the function() to a name and declare arguments within ()
new_function <- function(arguments) {
  # Write a function body within the {} to execute
  for (x in 1:arguments) {
    print("This is a function!")
  }
}

Here is an actual example

exampleFunction <- function(x, y) {
  c(x + 1, y + 10)
}

exampleFunction(2, 4)
[1]  3 14

Functions with Return Value

Functions in R return the last expression evaluated by default.

add_10 <- function(number) {
  number + 10
  # return (number+10)
}

add_10(5)
[1] 15
add_20 <- function(number) {
  return(number + 20) # Exit and return specified value
  number + 10 # The function exits before running this line
}

Function Arguments

A function can have one or more named arguments. You can assign a default value to an argument when creating a function with the argument_name = argument_value syntax.

sum_3_items <- function(x, y, z, print_args = TRUE) {
  if (print_args) {
    print(x)
    print(y)
    print(z)
  }
  return(x + y + z)
}
sum <- sum_3_items(1, 2, 3)
[1] 1
[1] 2
[1] 3
sum2 <- sum_3_items(10, 20, 30, print_args = FALSE)

Ellipsis

The … argument collects all extra arguments passed to a function that are not matched. The … argument can be used in functions where the number of arguments is not known in advance.

addition_function <- function(...) {
  total <- 0
  # list (...) extracts the arguments to a list
  for (value in list(...)) {
    # Add each argument in ... to the total
    total <- total + value
  }
  total
}

addition_function(2, 4, 6, 8, 10, 12, 14)
[1] 56

  1. De La Salle University, Manila, Philippines, ↩︎

LS0tDQp0aXRsZTogIkludHJvZHVjdGlvbiB0byBSIFN5bnRheCINCmF1dGhvcjogRGFwaG5lIEphbmVseW4gTC4gR29eW0RlIExhIFNhbGxlIFVuaXZlcnNpdHksIE1hbmlsYSwgUGhpbGlwcGluZXMsIGRhcGhuZV9qYW5lbHluX2dvQGRsc3UuZWR1LnBoXQ0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KUiBpcyBhbiBvcGVuIHNvdXJjZSBwcm9ncmFtbWluZyBsYW5ndWFnZSB0aGF0IGlzIHBvcHVsYXIgZm9yIHN0YXRpc3RpY3MgYW5kIGRhdGEgYW5hbHlzaXMuIFIgd2FzIGJ1aWx0IGJ5IHN0YXRpc3RpY2lhbnMsIHNvIG1hbnkgY29tbW9uIHN0YXRpc3RpY2FsIG9wZXJhdGlvbnMgYXJlIGJ1aWx0IGludG8gdGhlIGJhc2UgbGFuZ3VhZ2UuIFIgYWxzbyBmZWF0dXJlcyBwb3dlcmZ1bCBhbmQgaW50dWl0aXZlIGxpYnJhcmllcyBmb3IgcGxvdHRpbmcgYW5kIGEgdmFyaWV0eSBvZiBwYWNrYWdlcyBmb3IgcHJlZGljdGl2ZSBtb2RlbGluZywgbWFraW5nIGl0IG9uZSBvZiB0aGUgbW9zdCBwb3B1bGFyIGxhbmd1YWdlcyBmb3IgZGF0YSBzY2llbmNlLg0KDQojIyBEYXRhIFR5cGVzDQoNCkRlY2ltYWwgbnVtYmVycyAocmVhbCBudW1iZXJzKSBpbiBSIGFyZSBrbm93biBhcyBkb3VibGVzLiBEb3VibGVzIGFyZSB0aGUgZGVmYXVsdCBudW1lcmljIGRhdGEgdHlwZSBzbyB3aGVuIHlvdSBtYW51YWxseSBlbnRlciBhIG51bWJlciBpbiBSLCB5b3UgYXJlIHdvcmtpbmcgd2l0aCBhIGRvdWJsZS4NCg0KYGBge3J9DQp0eXBlb2YoMSkNCnR5cGVvZigtMTAuNSkNCnR5cGVvZihJbmYpDQp0eXBlb2YoLUluZikNCnR5cGVvZihOYU4pICMgZGl2aWRpbmcgemVybyBieSB6ZXJvIHByb2R1Y2VzIE5hTg0KYGBgDQoNCkludGVnZXJzIGFyZSBhIHNlY29uZCBudW1lcmljIGRhdGEgdHlwZSB0aGF0IG9ubHkgdGFrZSB3aG9sZSBudW1iZXJlZCB2YWx1ZXMuDQoNCmBgYHtyfQ0KYXMuaW50ZWdlcigxKSAjIENvbnZlcnQgdGhlIGRvdWJsZSAxIHRvIGludGVnZXIgMQ0KdHlwZW9mKGFzLmludGVnZXIoMSkpDQoNCiMgQ29udmVydCBiYWNrIGZyb20gaW50ZWdlciB0byBkb3VibGUNCmFzLm51bWVyaWMoYXMuaW50ZWdlcigxKSkNCmBgYA0KDQpPdXIgZmlyc3Qgbm9uLW51bWVyaWMgZGF0YSB0eXBlIGlzIHRoZSBMb2dpY2FsLiBBIExvZ2ljYWwgdGFrZXMgb24gdGhlIHZhbHVlIG9mIFRSVUUgb3IgRkFMU0UuIFlvdSBtdXN0IHR5cGUgVFJVRSBhbmQgRkFMU0UgaW4gYWxsIGNhcGl0YWwgbGV0dGVycyBmb3IgUiB0byByZWNvZ25pemUgdGhlbSBhcyBsb2dpY2FsIHZhbHVlcy4gRGF0YSB0aGF0IG9ubHkgdGFrZXMgb24gdGhlIHZhbHVlcyBvZiBUcnVlIG9yIEZhbHNlIGFyZSBhbHNvIGNhbGxlZCAiQm9vbGVhbnMiLg0KDQpgYGB7cn0NCnR5cGVvZihUUlVFKQ0KdHlwZW9mKEZBTFNFKQ0KdHlwZW9mKFQpDQp0eXBlb2YoRikNCmBgYA0KDQpZb3UgY2FuIGNyZWF0ZSBsb2dpY2FsIHZhbHVlcyB3aXRoIGxvZ2ljYWwgY29tcGFyaXNvbnMuIFIgc3VwcG9ydHMgYSB2YXJpZXR5IG9mIHN0YW5kYXJkIGxvZ2ljIGNvbXBhcmlzb24gb3BlcmF0b3JzIGluY2x1ZGluZyA+IChncmVhdGVyIHRoYW4pLCA8IChsZXNzIHRoYW4pLCA+PSAoZ3JlYXRlciB0aGFuIG9yIGVxdWFsKSwgPD0gKGxlc3MgdGhhbiBvciBlcXVhbCkuDQoNCmBgYHtyfQ0KMjAgPiAyMA0KMjAgPj0gMjANCjEwID09IDEwDQoxMCAhPSAyMA0KIUZBTFNFDQoNCigyID4gMSkgJiAoMTAgPT0gOSkNCigyID4gMSkgfCAoMTAgPT0gOSkNCmBgYA0KDQpTdHJpbmdzIG9mIHRleHQgaW4gUiBhcmUga25vd24gYXMgY2hhcmFjdGVycy4gU3Vycm91bmQgdGV4dCB3aXRoIHF1b3RhdGlvbiBtYXJrcyB0byBjcmVhdGUgYSBjaGFyYWN0ZXIuDQoNCmBgYHtyfQ0KdHlwZW9mKCJjYXQiKQ0KdHlwZW9mKCIxIikNCnR5cGVvZihhcy5udW1lcmljKCIxMiIpKQ0KdHlwZW9mKGFzLmNoYXJhY3RlcigxMikpDQpgYGANCg0KIyMgU2ltcGxlIEFyaXRobWV0aWMgT3BlcmF0aW9uc8K2DQoNCmBgYHtyfQ0KMTIgKyA2ICMgYWRkaXRpb24NCjEyIC0gNiAjIHN1YnRyYWN0aW9uDQoxMiAqIDYgIyBtdWx0aXBsaWNhdGlvbg0KMTIgLyA2ICMgZGl2aXNpb24NCjEyXjYgIyBleHBvbmVudGlhdGlvbg0KMTIqKjYgIyBleHBvbmVudGlhdGlvbg0KMTIgJSUgNiAjIG1vZHVsbyAoZ2V0IHJlbWFpbmRlcikNCmBgYA0KDQojIyBWYXJpYWJsZXMNCg0KQSB2YXJpYWJsZSBpcyBhIG5hbWUgeW91IGFzc2lnbiBhIHZhbHVlIG9yIG9iamVjdC4gQWZ0ZXIgYXNzaWduaW5nIGEgdmFyaWFibGUsIHlvdSBjYW4gYWNjZXNzIGl0cyBhc3NvY2lhdGVkIHZhbHVlIG9yIG9iamVjdCB1c2luZyB0aGUgdmFyaWFibGUncyBuYW1lLiBUbyBzaW1wbHkgcHV0LCB0aGlzIGlzIGhvdyB3ZSBzdG9yZSBkYXRhLiBJbiBSLCBhc3NpZ24gdmFyaWFibGVzIHVzaW5nIDwtICh0aGUgbGVzcyB0aGFuIHNpZ24gZm9sbG93ZWQgYnkgYSBoeXBoZW4uKS4NCg0KYGBge3J9DQp2YXIgPC0gMyArIDMNCnggPC0gMTANCnkgPC0gIlIgV29ya3Nob3AiDQp6IDwtIChzcXJ0KDE0NCkgPT0gMTIpDQoNCnByaW50KHZhcikNCnByaW50KHgpDQpwcmludCh5KQ0KcHJpbnQoeikNCmBgYA0KDQpJdCBpcyBwb3NzaWJsZSB0byBhc3NpZ24gdmFyaWFibGVzIGluIFIgdXNpbmcgdGhlIGVxdWFscyBzeW1ib2wgPSBpbnN0ZWFkIG9mIDwtLiBUaGUgZXF1YWwgc2lnbiBpcyB1c2VkIGZvciB2YXJpYWJsZSBhc3NpZ25tZW50IGluIG1hbnkgb3RoZXIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzIChzdWNoIGFzIFB5dGhvbikuIE9uZSByZWFzb24gZm9yIHVzaW5nIDwtIGJlc2lkZXMgY29uZm9ybWluZyB0byB0aGUgc3R5bGUgcHJlZmVycmVkIGJ5IHRoZSBSIGNvbW11bml0eSBpcyB0aGF0IHRoZSBlcXVhbHMgc2lnbiBpcyB1c2VkIGluIHBsYWNlcyBvdGhlciB0aGFuIHZhcmlhYmxlIGFzc2lnbm1lbnQgc3RhdGVtZW50cy4gRnVuY3Rpb25zIG9mdGVuIHRha2UgbmFtZWQgYXJndW1lbnRzIGFuZCB3aGVuIGNhbGxpbmcgYSBmdW5jdGlvbiB5b3UgdXNlIHRoZSA9IHN5bWJvbCB0byBhc3NpZ24gdmFsdWVzIHRvIG5hbWVkIGFyZ3VtZW50cy4NCg0KIyMgVmVjdG9ycyBvciBDb2xsZWN0aW9ucw0KDQpBIHZlY3RvciBpcyBhIHNlcXVlbmNlIG9mIGRhdGEgZWxlbWVudHMgb2YgdGhlIHNhbWUgZGF0YSB0eXBlLiBZb3UgY2FuIGhhdmUgbnVtZXJpYywgbG9naWNhbCBhbmQgY2hhcmFjdGVyIHZlY3RvcnMuDQoNClRvIGNyZWF0ZSBhbmQgc3RvcmUgYSB2ZWN0b3Igd2l0aCBzcGVjaWZpYyB2YWx1ZXMsIHVzZSB0aGUgYygpIGZ1bmN0aW9uIGFuZCBhc3NpZ24gdGhlIHJlc3VsdCB0byBhIHZhcmlhYmxlLiBjKCkgdGFrZXMgYSBjb21tYSBzZXBhcmF0ZWQgc2VxdWVuY2Ugb2YgZWxlbWVudHMgYXMgaW5wdXQgYW5kIGNvbWJpbmVzIHRoZW0gaW50byBhIHZlY3Rvci4gWW91IGNhbiBhbHNvIGNvbWJpbmUgdHdvIHZlY3RvcnMgdXNpbmcgdGhlIGMoKSBmdW5jdGlvbi4gSWYgeW91IHRyeSB0byBjb21iaW5lIHZlY3RvcnMgb2YgZGlmZmVyZW50IHR5cGVzLCBSIHdpbGwgYXV0b21hdGljYWxseSBjb252ZXJ0IHRoZSB2ZWN0b3JzIGludG8gdGhlIHR5cGUgdGhhdCBmaXRzIGJlc3QuDQoNCmBgYHtyfQ0KIyBDcmVhdGluZyBhIGNoYXJhY3RlciB2ZWN0b3IgZm9yIHRoZSBkYXlzIG9mIHRoZSB3ZWVrDQp3ZWVrZGF5IDwtIGMoIk1vbmRheSIsICJUdWVzZGF5IiwgIldlZG5lc2RheSIsICJUaHVyc2RheSIsICJGcmlkYXkiKQ0KDQp3ZWVrZW5kIDwtIGMoIlNhdHVyZGF5IiwgIlN1bmRheSIpDQoNCmRheXMgPC0gYyh3ZWVrZGF5LCB3ZWVrZW5kKQ0KDQpwcmludChkYXlzKQ0KYGBgDQoNCioqVmVjdG9yIEluZGV4aW5nIFN0YXJ0cyBhdCAxKioNCg0KVGhlIGZpcnN0IGVsZW1lbnQgaXMgYXQgaW5kZXggcG9zaXRpb24gMSwgdGhlIHNlY29uZCBlbGVtZW50IGlzIGF0IGluZGV4IHBvc2l0aW9uIDIgYW5kIHNvIG9uLg0KDQoqTm90ZTogdW5saWtlIG1hbnkgb3RoZXIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzLCBpbmRleGVzIGluIFIgc3RhcnQgYXQgMSBpbnN0ZWFkIG9mIDAuDQoNCldoZW4geW91IHByaW50IGEgdmVjdG9yIHRvIHRoZSBzY3JlZW4sIGVhY2ggbGluZSBzdGFydHMgd2l0aCBhIG51bWJlciBpbiBzcXVhcmUgYnJhY2tldHMgZm9sbG93ZWQgYnkgdmVjdG9yIHZhbHVlcy4gVGhlIG51bWJlciBpbiBzcXVhcmUgYnJhY2tldHMgaW5kaWNhdGVzIHRoZSBpbmRleCBvZiB0aGUgbmV4dCB2YWx1ZSBsaXN0ZWQgb24gdGhhdCBsaW5lLg0KDQpZb3UgY2FuIGFjY2VzcyBhIHNwZWNpZmljIHZhbHVlIGluIGEgdmVjdG9yIGJ5IHR5cGluZyB0aGUgbmFtZSBvZiB0aGUgdmVjdG9yIGFuZCB0aGVuIHdyYXBwaW5nIHRoZSBpbmRleCBhc3NvY2lhdGVkIHdpdGggdGhlIHZhbHVlIHlvdSB3YW50IHRvIGFjY2VzcyBpbiBzcXVhcmUgYnJhY2tldHMuDQoNCmBgYHtyfQ0KZGF5c1sxXQ0KYGBgDQoNCioqUmFuZ2Ugb2YgVmFsdWVzOiBJbmNsdXNpdmUqKg0KDQpZb3UgY2FuIGFjY2VzcyByYW5nZXMgb2YgdmFsdWVzIGJ5IHBsYWNpbmcgYSBjb2xvbiBiZXR3ZWVuIHRoZSBzdGFydGluZyBhbmQgZW5kaW5nIGluZGljZXMgb2YgdGhlIHJhbmdlOg0KDQpgYGB7cn0NCmRheXNbMTozXQ0KYGBgDQoNCioqUHVsbGluZyBvdXQgc3BlY2lmaWMgZWxlbWVudHMgZnJvbSBWZWN0b3JzKioNCg0KYGBge3J9DQpkYXlzW2MoMSwgMywgNSwgNyldDQpgYGANCg0KKipTdWJzZXQgb3V0IG9mIGEgQ29sbGVjdGlvbioqDQoNCkEgc3Vic2V0IG9mIGEgdmVjdG9yIGlzIGp1c3QgYSBzaG9ydGVyIHZlY3Rvci4gWW91IGNhbiBhY2Nlc3MgYSBzcGVjaWZpYyBzdWJzZXQgb2YgdmFsdWVzIGJ5IHdyYXBwaW5nIGEgdmVjdG9yIGluIHRoZSBzcXVhcmUgYnJhY2tldHMuDQoNCmBgYHtyfQ0Kd2Vla2RheXMgPC0gZGF5c1sxOjVdDQp3ZWVrZGF5cw0KYGBgDQoNCioqR2VuZXJhdGUgYSB2ZWN0b3IgdXNpbmcgMTAwIHJhbmRvbSBOdW1iZXJzKioNCg0KYGBge3J9DQpyYW5kb21fZGF0YSA8LSBydW5pZigxMDApICMgQ3JlYXRlIGEgdmVjdG9yIG9mIDEwMCByYW5kb20gbnVtYmVycw0KDQpwcmludChyYW5kb21fZGF0YSkNCnByaW50KGxlbmd0aChyYW5kb21fZGF0YSkpDQpgYGANCg0KKipGaWx0ZXJpbmcgb2YgVmVjdG9ycyB1c2luZyBMb2dpY2FsIEV4cHJlc3Npb25zKioNCllvdSBjYW4gYWxzbyBpbmRleCBhIHZlY3RvciB3aXRoIGEgbG9naWNhbCB2ZWN0b3Igb2YgdGhlIHNhbWUgbGVuZ3RoLiBJbiB0aGlzIGNhc2UsIHRoZSBzdWJzZXQgaXMgY3JlYXRlZCBmcm9tIGVhY2ggaW5kZXggd2hlcmUgdGhlIGNvcnJlc3BvbmRpbmcgbG9naWNhbCB2ZWN0b3IgaXMgVFJVRS4gSW5kZXhpbmcgd2l0aCBhIGxvZ2ljYWwgdmVjdG9yIGlzIGEgY29tbW9uIHdheSB0byBmaWx0ZXIgYSBudW1lcmljIG9yIGNoYXJhY3RlciB2ZWN0b3IgZm9yIHZhbHVlcyB0aGF0IGZ1bGZpbGwgY2VydGFpbiBjcml0ZXJpYS4NCg0KYGBge3J9DQojIEV4Y2x1ZGUgZXZlcnl0aGluZyBleGNlcHQgZm9yIHlvdXIgc3BlY2lmaWVkIGluZGV4DQoNCnkgPC0gYygxLCAwLCAzKQ0KeSA8LSB5Wy0yXQ0KeQ0KDQojIEV4Y2x1ZGUgdGhlIHJhbmdlIDIgdG8gOQ0KcmFuZG9tX2RhdGEgPC0gcnVuaWYoNTApDQpyYW5kb21fZGF0YV9zdWIgPC0gcmFuZG9tX2RhdGFbLSgyOjQ5KV0NCnJhbmRvbV9kYXRhX3N1Yg0KDQojIEV4Y2x1ZGUgdXNpbmcgbG9naWNhbCBleHByZXNzaW9uDQpvdmVyX2hhbGYgPC0gKHJhbmRvbV9kYXRhID4gMC41KQ0KbmV3X3N1YnNldCA8LSByYW5kb21fZGF0YVtvdmVyX2hhbGZdDQpuZXdfc3Vic2V0DQpgYGANCg0KKipVc2UgJWluJSB0byBmaWx0ZXIgYSB2ZWN0b3IqKg0KYGBge3J9DQpteV9sZXR0ZXJzIDwtIGMoImEiLCAiYiIsICJjIiwgImQiLCAiYSIsICJjIikNCg0KIyBHZXQgb25seSB0aGUgYSdzIGFuZCBjJ3MNCm15X2xldHRlcnNbbXlfbGV0dGVycyAlaW4lIGMoImEiLCAiYyIpXQ0KYGBgDQoNCiMjIFZlY3Rvcml6ZWQgT3BlcmF0aW9ucw0KDQpNYW55IFIgZnVuY3Rpb25zIGFuZCBvcGVyYXRpb25zIGJlaGF2ZSBpbiBhICJ2ZWN0b3JpemVkIiBtYW5uZXIsIG1lYW5pbmcgdGhleSBhY3QgdXBvbiBlYWNoIGVsZW1lbnQgb2YgYSB2ZWN0b3IgaW5kaXZpZHVhbGx5IGFuZCByZXR1cm4gdGhlIHJlc3VsdCBvZiBlYWNoIG9mIHRoZSBvcGVyYXRpb25zIGluIGEgbmV3IHZlY3Rvci4gVmVjdG9yaXplZCBvcGVyYXRpb25zIHNpbXBsaWZ5IHRoZSBwcm9jZXNzIG9mIHBlcmZvcm1pbmcgdGhlIHNhbWUgY2FsY3VsYXRpb25zIG9uIHJlbGF0ZWQgZGF0YS4gQWxsIHRoZSBiYXNpYyBvcGVyYXRvcnMgYW5kIGZ1bmN0aW9ucyB3ZSd2ZSBsZWFybmVkIHNvIGZhciB0aGF0IG9wZXJhdGUgb24gc2luZ2xlIHZhbHVlcyB3b3JrIG9uIHZlY3RvcnMgbG9uZ2VyIHRoYW4gbGVuZ3RoIDEuDQoNCmBgYHtyfQ0KZXhhbXBsZV92ZWN0b3IgPC0gYygxLCAyLCAzKQ0KDQojIGFkZHMgdG8gZWFjaCB2YWx1ZSBpbiB0aGUgdmVjdG9yDQpleGFtcGxlX3ZlY3RvciArIDEwDQoNCiMgcGVyZm9ybXMgc3VidHJhY3Rpb24gb24gZWFjaCB2YWx1ZQ0KZXhhbXBsZV92ZWN0b3IgLSAxMA0KYGBgDQoNCioqRGlmZmVyZW50IFdheXMgdG8gR2VuZXJhdGUgVmVjdG9ycyoqDQpgYGB7cn0NCnggPC0gMToyMA0KeSA8LSBzZXEoZnJvbSA9IDEsIHRvID0gMjAsIGJ5ID0gMikNCnIgPC0gcmVwKDEsIHRpbWVzID0gMTApDQpzIDwtIHJ1bmlmKG4gPSA1LCBtaW4gPSAwLCBtYXggPSAxMDApDQoNCngNCnkNCnINCnMNCmBgYA0KDQojIyBDb250cm9sIEZsb3cNCg0KIyMjIElmLCBFbHNlIGFuZCBFbHNlIElmDQoNCkFuIGlmIHN0YXRlbWVudCBjaGVja3Mgd2hldGhlciBzb21lIGxvZ2ljYWwgZXhwcmVzc2lvbiBpcyB0cnVlIG9yIGZhbHNlIGFuZCBleGVjdXRlcyBhIHNwZWNpZmllZCBibG9jayBvZiBjb2RlIGlmIHRoZSBsb2dpY2FsIGV4cHJlc3Npb24gaXMgdHJ1ZS4NCg0KSW4gUiwgYW4gaWYgc3RhdGVtZW50IHN0YXJ0cyB3aXRoIGlmLCBmb2xsb3dlZCBieSBhIGxvZ2ljYWwgZXhwcmVzc2lvbiBpbiBwYXJlbnRoZXNlcywgZm9sbG93ZWQgYnkgdGhlIGNvZGUgdG8gZXhlY3V0ZSB3aGVuIHRoZSBpZiBzdGF0ZW1lbnQgaXMgdHJ1ZSBpbiBjdXJseSBicmFjZXMuDQoNCklmIHN0YXRlbWVudHMgYXJlIG9mdGVuIGFjY29tcGFuaWVkIGJ5IGVsc2Ugc3RhdGVtZW50cy4gRWxzZSBzdGF0ZW1lbnRzIGNvbWUgYWZ0ZXIgaWYgc3RhdGVtZW50cyBhbmQgYWxsb3cgeW91IHRvIGV4ZWN1dGUgY29kZSBpbiB0aGUgZXZlbnQgdGhhdCB0aGUgbG9naWNhbCBleHByZXNzaW9uIG9mIGFuIGlmIHN0YXRlbWVudCBpcyBmYWxzZS4NCg0KYGBge3J9DQp4IDwtIDUNCmlmICh4ID4gMCkgew0KICBwcmludCgiUG9zaXRpdmUgbnVtYmVyIikNCn0gZWxzZSB7DQogIHByaW50KCJOZWdhdGl2ZSBudW1iZXIiKQ0KfQ0KYGBgDQoNCiMjIyBGb3IgTG9vcHMNCg0KRm9yIGxvb3BzIGFyZSBhIHByb2dyYW1taW5nIGNvbnN0cnVjdCB0aGF0IGxldCB5b3UgZ28gdGhyb3VnaCBlYWNoIGl0ZW0gaW4gYSBzZXF1ZW5jZSBhbmQgdGhlbiBwZXJmb3JtIHNvbWUgb3BlcmF0aW9uIG9uIGVhY2ggb25lLg0KDQpgYGB7cn0NCm15X3NlcXVlbmNlIDwtIHNlcSgwLCAxMDAsIDEwKQ0KDQojIENyZWF0ZSBhIG5ldyBsb29wIG92ZXIgdGhlIHNwZWNpZmllZCBpdGVtcw0KZm9yIChpdGVtIGluIG15X3NlcXVlbmNlKSB7DQogIHByaW50KGl0ZW0pDQp9DQpgYGANCg0KKipUaGUgbmV4dCBrZXl3b3JkIGNhdXNlcyBhIGZvciBsb29wIHRvIHNraXAgdG8gdGhlIG5leHQgaXRlcmF0aW9uIG9mIHRoZSBsb29wLioqDQoNCmBgYHtyfQ0KbXlfc2VxdWVuY2UgPC0gc2VxKDAsIDEwMCwgMTApDQpmb3IgKGl0ZW0gaW4gbXlfc2VxdWVuY2UpIHsNCiAgaWYgKGl0ZW0gPCA1MCkgeyAjIHRoaXMgaWYgc3RhdGVtZW50IHNraXBzIGl0ZW1zIGxlc3MgdGhhbiA1MA0KICAgIG5leHQNCiAgfQ0KICBwcmludChpdGVtKQ0KfQ0KYGBgDQoNCioqVGhlIGJyZWFrIGtleXdvcmQgaGFsdHMgdGhlIGV4ZWN1dGlvbiBvZiB0aGUgbG9vcCBlbnRpcmVseS4gVXNlIGJyZWFrIHRvIGJyZWFrIG91dCBvZiBhIGxvb3AuKioNCg0KYGBge3J9DQpteV9zZXF1ZW5jZSA8LSBzZXEoMCwgMTAwLCAxMCkNCg0KZm9yIChpdGVtIGluIG15X3NlcXVlbmNlKSB7DQogIGlmIChpdGVtID4gNTApIHsNCiAgICBicmVhaw0KICB9DQogIHByaW50KGl0ZW0pDQp9DQpgYGANCg0KIyMjIFdoaWxlIExvb3BzDQoNCldoaWxlIGxvb3BzIGFyZSBzaW1pbGFyIHRvIGZvciBsb29wcyBpbiB0aGF0IHRoZXkgYWxsb3cgeW91IHRvIGV4ZWN1dGUgY29kZSBvdmVyIGFuZCBvdmVyIGFnYWluLiBGb3IgbG9vcHMgZXhlY3V0ZSB0aGVpciBjb250ZW50cywgYXQgbW9zdCwgYSBudW1iZXIgb2YgaXRlcmF0aW9ucyBlcXVhbCB0byB0aGUgbGVuZ3RoIG9mIHRoZSBzZXF1ZW5jZSB5b3UgYXJlIGxvb3Bpbmcgb3Zlci4gV2hpbGUgbG9vcHMsIG9uIHRoZSBvdGhlciBoYW5kLCAqKmtlZXAgZXhlY3V0aW5nIHRoZWlyIGNvbnRlbnRzIGFzIGxvbmcgYXMgYSBjZXJ0YWluIGxvZ2ljYWwgZXhwcmVzc2lvbiB5b3Ugc3VwcGx5IHJlbWFpbnMgdHJ1ZS4qKg0KDQpgYGB7cn0NCnggPC0gNQ0KaXRlcmF0aW9ucyA8LSAwDQoNCiMgRXhlY3V0ZSBhcyBsb25nIGFzIGl0ZXJhdGlvbnMgPCB4DQp3aGlsZSAoaXRlcmF0aW9ucyA8IHgpIHsNCiAgcHJpbnQoIlN0dWR5IikNCiAgaXRlcmF0aW9ucyA8LSBpdGVyYXRpb25zICsgMSAjIEluY3JlbWVudCBpdGVyYXRpb25zIGJ5IDEgZWFjaCB0aW1lIHRoZSBsb29wIGV4ZWN1dGVzDQp9DQpgYGANCg0KIyMjIElmIEVsc2Ugb24gVmVjdG9ycw0KRm9yIGV4YW1wbGUsIGltYWdpbmUgeW91IGhhdmUgYSB2ZWN0b3Igb2YgbnVtYmVycyBhbmQgeW91IHdhbnQgdG8gc2V0IGFsbCB0aGUgbmVnYXRpdmUgdmFsdWVzIGluIHRoZSB2ZWN0b3IgdG8gemVyby4gT25lIHdheSB0byBkbyBpdCBpcyB0byB1c2UgYSBmb3IgbG9vcCB3aXRoIGFuIGlubmVyIGlmIHN0YXRlbWVudC4NCg0KYGBge3J9DQpteV92ZWN0IDwtIHJ1bmlmKDI1LCAtMSwgMSkgIyBHZW5lcmF0ZSBzb21lIHJhbmRvbSBkYXRhIGJldHdlZW4gLTEgYW5kIDENCg0KZm9yIChpbmRleCBpbiAxOmxlbmd0aChteV92ZWN0KSkgeyAjIGxvb3AgdGhyb3VnaCB0aGUgc2VxdWVuY2UgMToyNQ0KICBudW1iZXIgPC0gbXlfdmVjdFtpbmRleF0gIyBsb29rIHVwIHRoZSBuZXh0IG51bWJlciB1c2luZyBpbmRleGluZw0KICBpZiAobnVtYmVyIDwgMCkgeyAjIGNoZWNrIGlmIHRoZSBudW1iZXIgaXMgbGVzcyB0aGFuIDANCiAgICBteV92ZWN0W2luZGV4XSA8LSAwICMgaWYgc28sIHNldCBpdCB0byAwDQogIH0NCn0NCg0KcHJpbnQobXlfdmVjdCkNCmBgYA0KDQpVc2luZyBhIGZvciBsb29wIHJlcXVpcmVzIHdyaXRpbmcgcXVpdGUgYSBiaXQgb2YgY29kZSBhbmQgbG9vcHMgYXJlIG5vdCBwYXJ0aWN1bGFybHkgZmFzdC4NCg0KSW5zdGVhZCB3ZSBjb3VsZCBoYXZlIHVzZWQgUidzIGlmZWxzZSgpIGZ1bmN0aW9uIHRvIHRoZSBzYW1lIHRoaW5nIGluIGEgdmVjdG9yaXplZCBtYW5uZXIuIGlmZWxzZSgpIHRha2VzIGEgbG9naWNhbCB0ZXN0IGFzIHRoZSBmaXJzdCBhcmd1bWVudCwgYSB2YWx1ZSB0byByZXR1cm4gaWYgdGhlIHRlc3QgaXMgdHJ1ZSBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IGFuZCBhIHZhbHVlIHRvIHJldHVybiBpZiB0aGUgdGVzdCBpcyBmYWxzZSBhcyB0aGUgdGhpcmQgYXJndW1lbnQ6DQoNCmBgYHtyfQ0KZGF0YSA8LSBjKDExLCA3LCBOQSwgOSwgTkEsIDEzLCAxNSwgTmFOLCAxOSwgMTcsIDE0LCBOYU4pDQoNCiMgVXNlIGlmIGVsc2Ugc3RhdGVtZW50cyB0byBjb25kaXRpb25hbGx5IGZpbGwgdGhlc2UgYmFkIHZhbHVlcyB3aXRoIHRoZSBtZWFuDQoNCmlmZWxzZShpcy5uYShkYXRhKSB8IGlzLm5hbihkYXRhKSwgIyBsb2dpY2FsIGNoZWNrDQogIG1lYW4oZGF0YSwgbmEucm0gPSBUKSwgIyB2YWx1ZSB0byBzZXQgaWYgVFJVRQ0KICBkYXRhDQopICMgdmFsdWUgdG8gc2V0IGlmIEZBTFNFDQpgYGANCg0KYGBge3J9DQojIENoYWluaW5nIGlmZWxzZSB0byBwZXJmb3JtIG11bHRpcGxlIG9wZXJhdGlvbnMNCmRhdGEgPC0gYygxMSwgNywgTkEsIDksIE5BLCAxMywgMTUsIE5hTiwgMTksIDE3LCAxNCwgTmFOKQ0KDQpkIDwtIGlmZWxzZShpcy5uYShkYXRhKSB8IGlzLm5hbihkYXRhKSwgIm1pc3NpbmciLCBpZmVsc2UoZGF0YSA8IDEwLCAibG93IiwgaWZlbHNlKGRhdGEgPCAxNSwgIm1lZGl1bSIsICJoaWdoIikpKQ0KDQp0YWJsZShkKQ0KYGBgDQoNCiMjIEZ1bmN0aW9ucw0KQSBmdW5jdGlvbiBpcyBqdXN0IGFuIFIgb2JqZWN0IHRoYXQgcnVucyBhIHBlci1kZWZpbmVkIHNuaXBwZXQgb2YgY29kZSwgdXN1YWxseSBvbiBzb21lIGlucHV0IHRoYXQgeW91IHN1cHBseSB0byBpdC4gQSBmdW5jdGlvbiBjYW4gcmV0dXJuIGFuIG91dHB1dCBiYXNlZCBvbiB0aGUgaW5wdXQgeW91IHByb3ZpZGUuIEZvciBleGFtcGxlLCB0aGUgc3VtKCkgZnVuY3Rpb24gYnVpbHQgaW50byBSIHNpbXBseSB0YWtlcyBhIG51bWVyaWMgdmVjdG9yIGFzIGlucHV0IGFuZCByZXR1cm5zIHRoZWlyIHN1bSBhcyBvdXRwdXQuIEJ1aWx0LWluIGZ1bmN0aW9ucyBhbmQgcGFja2FnZXMgY2FuIHRha2UgeW91IGEgbG9uZyB3YXkgaW4gUiwgYnV0IGl0IGNhbiBiZSB1c2VmdWwgdG8gZGVmaW5lIHlvdXIgb3duIGZ1bmN0aW9ucyB0byBwZXJmb3JtIHNwZWNpZmljIHRhc2tzIG91dHNpZGUgdGhlIHNjb3BlIG9mIGJ1aWx0LWluIGZ1bmN0aW9ucy4NCg0KQ3JlYXRlIHlvdXIgb3duIGZ1bmN0aW9uIGluIFIgdXNpbmcgdGhpcyBzeW50YXg6DQoNCmBgYHtyfQ0KIyBBc3NpZ24gdGhlIGZ1bmN0aW9uKCkgdG8gYSBuYW1lIGFuZCBkZWNsYXJlIGFyZ3VtZW50cyB3aXRoaW4gKCkNCm5ld19mdW5jdGlvbiA8LSBmdW5jdGlvbihhcmd1bWVudHMpIHsNCiAgIyBXcml0ZSBhIGZ1bmN0aW9uIGJvZHkgd2l0aGluIHRoZSB7fSB0byBleGVjdXRlDQogIGZvciAoeCBpbiAxOmFyZ3VtZW50cykgew0KICAgIHByaW50KCJUaGlzIGlzIGEgZnVuY3Rpb24hIikNCiAgfQ0KfQ0KYGBgDQoNCkhlcmUgaXMgYW4gYWN0dWFsIGV4YW1wbGUNCg0KYGBge3J9DQpleGFtcGxlRnVuY3Rpb24gPC0gZnVuY3Rpb24oeCwgeSkgew0KICBjKHggKyAxLCB5ICsgMTApDQp9DQoNCmV4YW1wbGVGdW5jdGlvbigyLCA0KQ0KYGBgDQoNCioqRnVuY3Rpb25zIHdpdGggUmV0dXJuIFZhbHVlKioNCg0KRnVuY3Rpb25zIGluIFIgcmV0dXJuIHRoZSBsYXN0IGV4cHJlc3Npb24gZXZhbHVhdGVkIGJ5IGRlZmF1bHQuDQoNCmBgYHtyfQ0KYWRkXzEwIDwtIGZ1bmN0aW9uKG51bWJlcikgew0KICBudW1iZXIgKyAxMA0KICAjIHJldHVybiAobnVtYmVyKzEwKQ0KfQ0KDQphZGRfMTAoNSkNCg0KYWRkXzIwIDwtIGZ1bmN0aW9uKG51bWJlcikgew0KICByZXR1cm4obnVtYmVyICsgMjApICMgRXhpdCBhbmQgcmV0dXJuIHNwZWNpZmllZCB2YWx1ZQ0KICBudW1iZXIgKyAxMCAjIFRoZSBmdW5jdGlvbiBleGl0cyBiZWZvcmUgcnVubmluZyB0aGlzIGxpbmUNCn0NCmBgYA0KDQoNCiMjIEZ1bmN0aW9uIEFyZ3VtZW50cw0KDQpBIGZ1bmN0aW9uIGNhbiBoYXZlIG9uZSBvciBtb3JlIG5hbWVkIGFyZ3VtZW50cy4gWW91IGNhbiBhc3NpZ24gYSBkZWZhdWx0IHZhbHVlIHRvIGFuIGFyZ3VtZW50IHdoZW4gY3JlYXRpbmcgYSBmdW5jdGlvbiB3aXRoIHRoZSBhcmd1bWVudF9uYW1lID0gYXJndW1lbnRfdmFsdWUgc3ludGF4Lg0KDQpgYGB7cn0NCnN1bV8zX2l0ZW1zIDwtIGZ1bmN0aW9uKHgsIHksIHosIHByaW50X2FyZ3MgPSBUUlVFKSB7DQogIGlmIChwcmludF9hcmdzKSB7DQogICAgcHJpbnQoeCkNCiAgICBwcmludCh5KQ0KICAgIHByaW50KHopDQogIH0NCiAgcmV0dXJuKHggKyB5ICsgeikNCn0NCnN1bSA8LSBzdW1fM19pdGVtcygxLCAyLCAzKQ0Kc3VtMiA8LSBzdW1fM19pdGVtcygxMCwgMjAsIDMwLCBwcmludF9hcmdzID0gRkFMU0UpDQpgYGANCg0KKipFbGxpcHNpcyoqDQoNClRoZSAuLi4gYXJndW1lbnQgY29sbGVjdHMgYWxsIGV4dHJhIGFyZ3VtZW50cyBwYXNzZWQgdG8gYSBmdW5jdGlvbiB0aGF0IGFyZSBub3QgbWF0Y2hlZC4gVGhlIC4uLiBhcmd1bWVudCBjYW4gYmUgdXNlZCBpbiBmdW5jdGlvbnMgd2hlcmUgdGhlIG51bWJlciBvZiBhcmd1bWVudHMgaXMgbm90IGtub3duIGluIGFkdmFuY2UuDQoNCg0KYGBge3J9DQphZGRpdGlvbl9mdW5jdGlvbiA8LSBmdW5jdGlvbiguLi4pIHsNCiAgdG90YWwgPC0gMA0KICAjIGxpc3QgKC4uLikgZXh0cmFjdHMgdGhlIGFyZ3VtZW50cyB0byBhIGxpc3QNCiAgZm9yICh2YWx1ZSBpbiBsaXN0KC4uLikpIHsNCiAgICAjIEFkZCBlYWNoIGFyZ3VtZW50IGluIC4uLiB0byB0aGUgdG90YWwNCiAgICB0b3RhbCA8LSB0b3RhbCArIHZhbHVlDQogIH0NCiAgdG90YWwNCn0NCg0KYWRkaXRpb25fZnVuY3Rpb24oMiwgNCwgNiwgOCwgMTAsIDEyLCAxNCkNCmBgYA==